package it.gnocco.ann;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;

import it.gnocco.grafo.Nodo;
import it.gnocco.log.Logger;
import it.gnocco.state.HashStati;
import it.gnocco.state.Stato;

import com.heatonresearch.book.introneuralnet.neural.feedforward.*;
import com.heatonresearch.book.introneuralnet.neural.feedforward.train.*;
import com.heatonresearch.book.introneuralnet.neural.feedforward.train.backpropagation.*;

public class NeuralNetwork {
	
	public FeedforwardNetwork network = null;
	
	public static double INPUT[][] = { { 0.0, 0.0 }, { 1.0, 0.0 },	{ 0.0, 1.0 }, { 1.0, 1.0 } };

	public static double IDEAL[][] = { { 0.0 }, { 1.0 }, { 1.0 }, { 0.0 } };

	public FeedforwardNetwork impara(HashStati S, int nodi, int robot){
		estrapolaDataSet(S, nodi, robot);
		network = new FeedforwardNetwork();
		network.addLayer(new FeedforwardLayer(nodi+robot));
		network.addLayer(new FeedforwardLayer((nodi+robot)*2));
		network.addLayer(new FeedforwardLayer(1));
		network.reset();
	
		// train the neural network
		final Train train = new Backpropagation(network, INPUT, IDEAL, 0.0006, 0.012);
		System.out.println("Dim DataSet = " + INPUT.length);
		
		int epoch = 1;
	
		do {
			train.iteration();
			System.out.println("Epoch #" + epoch + " Error:" + train.getError());
			epoch++;
		} while ((epoch < 5000) && (train.getError() > 0.001));
	
		// test the neural network
		System.out.println("Neural Network Results:");
		for (int i = 0; i < IDEAL.length; i++) {
			final double actual[] = network.computeOutputs(INPUT[i]);
			System.out.println("actual=" + actual[0] + ",ideal=" + IDEAL[i][0]);
		}
		return network;
	}
	
	void estrapolaDataSet(HashStati S, int nodi, int robot){
		ArrayList<double[]> input = new ArrayList<double[]>();
		ArrayList<double[]> ideal = new ArrayList<double[]>();
		//INPUT = new double[S.size()][nodi + robot];
		//IDEAL = new double[S.size()][1];
		String METHOD = "stampaStati";
		int t = 0;
		for(int i = 0; i < S.array.size(); i++){
			HashSet<Stato> hs = S.array.get(i);
			Iterator<Stato> iter = hs.iterator();
			while(iter.hasNext()){
				Stato st = iter.next();
				double[] val = new double[1];
				if(st.value!= -1.0){
					val[0] = st.value/100.0;
					input.add(formattaINPUT(st,nodi,robot));
					ideal.add(val);
				}
			}
		}
		INPUT = new double[input.size()][nodi + robot];
		IDEAL = new double[input.size()][1];
		for(int j = 0; j < input.size(); j++){
			INPUT[j] = input.get(j);
			IDEAL[j] = ideal.get(j);
		}
	}

	public static double[] formattaINPUT(Stato st, int nodi, int robot){
		double[] riga = new double[nodi + robot];
		for(int j = 0; j < nodi; j++){
			if(st.visitati.contains(new Nodo(j))){
				riga[j] = 100.0;
			} else {
				riga[j] = -100.0;
			}
		}
		for(int j = 0; j < robot; j++){
			riga[nodi+j] = st.robot.get(j).getPosizione().getID()*10;
		}
		return riga;
	}


}
